//! # 网络层
//!
//! 网络层(net)规定了数据包格式(Packet)，负责维护路由表

mod history;
mod packet;
mod route;

use crate::feature;
use crate::id::*;
use crate::link::Link;
use crate::protocol;
use core::sync::atomic::{AtomicU8, Ordering};
use log::{info, warn};
use packet::{Field, Packet};
pub use route::get_link;
pub use route::info as route_info;
use spin::Lazy;
use spin::RwLock;

static SN: Lazy<AtomicU8> = Lazy::new(|| {
    AtomicU8::new({
        let mut data: [u8; 1] = [0; 1];
        getrandom::getrandom(&mut data).unwrap();
        data[0]
    })
});
static CFG: RwLock<Config> = RwLock::new(Config {
    id: Id::new(),
    relay: false,
    auth: None,
});

/// 配置
pub struct Config {
    /// 本设备ID
    pub id: Id,
    /// 转发开关
    pub relay: bool,
    /// 鉴权函数
    pub auth: Option<fn(src: &Id, dst: &Id) -> bool>,
}

/// 初始化
pub fn init(cfg: Config) {
    *CFG.write() = cfg;
    feature::init();
}
/// 读取本机ID
pub fn get_id() -> Id {
    return CFG.read().id.clone();
}
/// 通用发送函数
fn send_common(
    packet: &mut Packet,
    dst: Option<&Id>,
    dst_link: Option<Link>,
    origin: Option<Link>,
) {
    let id: &Id = if let Some(id) = dst {
        packet.set_var(Field::Dst, &id);
        id
    } else {
        &packet.dst
    };
    if let Some(link) = dst_link {
        if let Some(origin) = origin {
            if origin == link {
                return;
            }
        }
        let buf = packet.to_buf();
        if feature::offline::is_enabled(id) {
            feature::offline::push(id, &buf);
            return;
        }
        let _err = link.send(&buf);
    } else {
        let buf = packet.to_buf();
        if dst == Some(&ID_ALL) {
            Link::broadcast(&buf);
            return;
        }
        if feature::offline::is_enabled(id) {
            feature::offline::push(id, &buf);
            return;
        }
        let err1 = route::sendto(id, &buf, origin);
        let err2 = route::sendto(&ID_PARENT, &buf, origin);
        if let (Err(_), Err(_)) = (err1, err2) {
            warn!("unmp can't find router.");
        }
    }
}
pub fn pack(protocol: u8, data: &[u8], id: &Id) -> Packet {
    let mut packet = Packet::new();
    packet.sn = SN.fetch_add(1, Ordering::Relaxed);
    packet.set_var(Field::Protocol, &[protocol]);
    packet.set_var(Field::Data, data);
    packet.set_var(Field::Src, &CFG.read().id);
    if id == &ID_ALL {
        packet.set_var(Field::Ttl, &[0]);
    } else {
        packet.set_var(Field::Ttl, &[8]);
    }
    packet
}
/// 发送数据包到指定设备
pub fn send(protocol: u8, data: &[u8], id: &Id, link: Option<Link>) {
    let mut packet = pack(protocol, data, id);
    send_common(&mut packet, Some(id), link, None);
}
/// 收到了数据包
pub fn when_recv(link: Link, buf: &[u8]) {
    info!("{} recv:{:02X?}.", link, buf);
    let mut packet = match Packet::try_from_buf(buf) {
        Ok(packet) => packet,
        Err(err) => {
            warn!("net recv err: {}", err);
            return;
        }
    };
    if history::has(&packet) {
        info!("net packet repeat.");
        return;
    }
    history::add(&packet);
    if let Some(auth) = CFG.read().auth {
        if !auth(&packet.src, &packet.dst) {
            warn!("net auth fail.");
            return;
        }
    }

    if packet.src != ID_PARENT && packet.src != ID_ALL {
        connect(&packet.src, link);
    }

    if packet.dst == CFG.read().id || packet.dst == ID_PARENT || packet.dst == ID_ALL {
        protocol::distribute(packet.protocol, &packet.src, &packet.data);
    } else if CFG.read().relay {
        if packet.ttl > 0 {
            packet.set_var(Field::Ttl, &[packet.ttl - 1]);
            send_common(&mut packet, None, None, Some(link));
        } else {
            info!("unmp TTL is 0.");
        }
    }
}
/// 更新路由
pub fn connect(id: &Id, link: Link) {
    route::add(id, link);
}
